// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © thelogicaldude

// Logical Trading Indicator version 1.3 Release

//@version=5
indicator(title='Logical Trading Indicator V.1', shorttitle='LT Indicator V.1', overlay=true, timeframe="", timeframe_gaps=true)

// *********** ATR Settings for Trailing Stop Loss *************

// Input Variables
atr_multiple = input.float(2.0, title='ATR Multiple', group="ATR Options", step=0.5, tooltip="The ATR Multiple determines the sensitivity of the alerts. A higher value will result in tighter stops, while a lower value will create wider stops. Suggested settings for 5min-1HR timeframes: 1.0-3.0. For 2HR and above: 2.0-5.0. Default value set to 3.0")
atr_per = input(4, title='ATR Period', group="ATR Options", tooltip='The ATR Period determines the number of periods used to calculate the Average True Range (ATR). A higher value will consider more historical data, providing a smoother ATR line, but it may respond more slowly to recent price changes. A lower value will make the ATR line more sensitive to recent price changes, but it might generate more false signals. Suggested settings for 5min-1HR timeframes: 5-15. 2HR and above: 20-50. Default value set to 7')

// Calculate ATR (Average True Range) and determine the loss value
atr_val = ta.atr(atr_per)
stopLoss = atr_multiple * atr_val

// Use regular candlesticks as the data source
hsrc = close

// Calculate the trailing stop based on price movements
ATRTrailingStop = 0.0
val_1 = hsrc > nz(ATRTrailingStop[1], 0) ? hsrc - stopLoss : hsrc + stopLoss
val_2 = hsrc < nz(ATRTrailingStop[1], 0) and hsrc[1] < nz(ATRTrailingStop[1], 0) ? math.min(nz(ATRTrailingStop[1]), hsrc + stopLoss) : val_1
ATRTrailingStop := hsrc > nz(ATRTrailingStop[1], 0) and hsrc[1] > nz(ATRTrailingStop[1], 0) ? math.max(nz(ATRTrailingStop[1]), hsrc - stopLoss) : val_2

// Determine the position (buy, sell, or hold)
pos = 0
val_3 = hsrc[1] > nz(ATRTrailingStop[1], 0) and hsrc < nz(ATRTrailingStop[1], 0) ? -1 : nz(pos[1], 0)
pos := hsrc[1] < nz(ATRTrailingStop[1], 0) and hsrc > nz(ATRTrailingStop[1], 0) ? 1 : val_3

// ************ Bollinger Bands ***************

// Bollinger Bands Options
basis_type = input.string("EMA", title="Basis Type", options=["SMA", "EMA"], group = "Bollinger Band Options", tooltip = 'Choose if you want the Bollinger Band to be based on a simple or exponential moving average.')
basis_length = input.int(18, minval=1, group = "Bollinger Band Options", tooltip = 'Set the length of the Bollinger Band basis moving average. The lower the number, the more sensitive to price action. Default value is 20.')
BB_src = input(close, title="BB Source")
mult = input.float(2, minval=0.001, maxval=50, title="StdDev", group = "Bollinger Band Options", step = 0.25, tooltip='Standard deviation multiplier for calculating the upper and lower Bollinger Bands. Lower values make the bands more sensitive to price action. Default value: 2.')
mult2 = mult + 1
offset = input.int(0, "Offset", minval = -500, maxval = 500, group = "Bollinger Band Options", tooltip="Bollinger Band offset. Enter a positive value to shift the bands to the right, a negative value to shift them to the left, and 0 to keep them at their original position. This can be used to prevent overlap of other indicators, anticipate price action, and can be used in backtesting.")

// Calculate the basis based on the selected basis type
basis = basis_type == "EMA" ? ta.ema(BB_src, basis_length) : ta.sma(BB_src, basis_length)

dev = mult * ta.stdev(BB_src, basis_length)
dev2 = mult2 * ta.stdev(BB_src, basis_length)
upper = basis + dev
upper2 = basis + dev2
lower = basis - dev
lower2 = basis - dev2

// Input variable to toggle Bollinger Bands visibility
showBollingerBands = input(true, title="Show Bollinger Bands", group = "Bollinger Band Options", tooltip="Toggle the visibility of the upper and lower Bollinger Bands. The basis line will remain and can be toggled in the style settings.")

// Input variables for Bollinger Bands colors
upperBandColor = input(color.rgb(255, 255, 255, 80), title="Upper Band Color", group = "Bollinger Band Options", inline="1")
lowerBandColor = input(color.rgb(255, 255, 255, 80), title="Lower Band Color", group = "Bollinger Band Options", inline="1")

// Plotting Bollinger Bands on the chart
basis_color = close > basis ? color.green : color.red
plot(basis, "Basis", color=basis_color, offset = offset, linewidth = 3)
p1 = plot(showBollingerBands ? upper : na, "Upper", color=upperBandColor, offset = offset)
p2 = plot(showBollingerBands ? lower : na, "Lower", color=lowerBandColor, offset = offset)
p3 = plot(showBollingerBands ? upper2 : na, "Upper2", color=upperBandColor, offset = offset)
p4 = plot(showBollingerBands ? lower2 : na, "Lower2", color=lowerBandColor, offset = offset)

// Setting fill colors of the upper and lower bands
fill(p1, p2, title = "Main Background", color=color.rgb(33, 149, 243, 96))
fill(p1, p3, title = "Upper Background", color= upperBandColor)
fill(p2, p4, title = "Lower Background", color= lowerBandColor)


// Setting crossover points based on the moving average from the Bolliner Band and the calculations from the trailing stop loss. 
BasisEMA = ta.ema(hsrc, basis_length)
aboveBasis = ta.crossover(BasisEMA, ATRTrailingStop)
belowBasis = ta.crossunder(BasisEMA, ATRTrailingStop)

// ************ Momentum Indicator settings ************

// Additional Input to Enable/Disable Momentum Indicator Options
showBarColor = input(true, title='Show Momentum Bar Color', group="Momentum Indicator Options", tooltip = "Show bar color based on market momentum, bullish, bearish, or neutral which is consolidation.")
enable_consolidation = input.bool(false, "Enable Consolidation Filter", group="Momentum Indicator Options", tooltip="Enable this to turn off BUY and SELL signals during market consolidation. This keeps you out of trades during tight ranges.")

// Momentum Variables - Bollinger Band and Keltner Channel Squeeze
bbLength     = basis_length
kcLength     = basis_length
bbMult       = 2.25
kcMult       = 1.25
plot_length  = 2000

// Making Calculations based on the Bollinger band and Keltner Channel settings. This shows consolidation in the market

[_, bbUpper, bbLower] = ta.bb(hsrc, bbLength, bbMult)
[_, kcUpper, kcLower] = ta.kc(hsrc, kcLength, kcMult)

bbkcSqueeze  = bbLower > kcLower and bbUpper < kcUpper
momentum = bbLower < kcLower and bbUpper > kcUpper
noSqueeze  = bbkcSqueeze == false and momentum == false

osc2    = ta.linreg(hsrc - math.avg(math.avg(ta.highest(high, kcLength), ta.lowest(low, kcLength)), ta.sma(hsrc, kcLength)), kcLength, 0)
signal = ta.sma(osc2, basis_length)
dir    = osc2 - signal

// Determine the bar color based on the position status and squeeze status
candleColor = bbkcSqueeze or noSqueeze
barcolor(showBarColor ? (candleColor ? color.white : pos == 1 ? color.green : pos == -1 ? color.red : na) : na)

// ************ BUY and SELL Signals **************

// Define initial position
var int position = na

// Modify the buy and sell conditions to include the ATR-based filter and momentum condition
buy = hsrc > ATRTrailingStop and aboveBasis and (enable_consolidation == false or momentum)
sell = hsrc < ATRTrailingStop and belowBasis and (enable_consolidation == false or momentum)

// Check for position and generate signals accordingly
if buy
    position := 1
else if sell
    position := -1

// Filter multiple signals
buy := position[1] == -1 and buy
sell := position[1] == 1 and sell

// Plot buy and sell signals as shapes on the chart
plotshape(buy, title='Buy', style=shape.labelup, location=location.belowbar, color=color.green, size=size.small)
plotshape(sell, title='Sell', style=shape.labeldown, location=location.abovebar, color=color.red, size=size.small)

// ************ Take Profit Signals ***************

// Setting the Take Profit markers based on crossover or crossunder of the lower or upper bollinger band lines
longTakeProfit = ta.crossunder(hsrc, upper)
shortTakeProfit = ta.crossover(hsrc, lower)

// Variables to track if a longTakeProfit or shortTakeProfit has been plotted for the current buy or sell signal
var bool longTakeProfitPlotted = false
var bool shortTakeProfitPlotted = false
bool plotLongTakeProfit = false
bool plotShortTakeProfit = false

// Check for longTakeProfit condition and plotshape if it's true and not already plotted
if (longTakeProfit and not longTakeProfitPlotted)
    plotLongTakeProfit := true

// Check for shortTakeProfit condition and plotshape if it's true and not already plotted
if (shortTakeProfit and not shortTakeProfitPlotted)
    plotShortTakeProfit := true

// Update the longTakeProfitPlotted and shortTakeProfitPlotted
if (buy)
    longTakeProfitPlotted := false
else
    longTakeProfitPlotted := longTakeProfitPlotted or plotLongTakeProfit

if (sell)
    shortTakeProfitPlotted := false
else
    shortTakeProfitPlotted := shortTakeProfitPlotted or plotShortTakeProfit

// Plot take profit markers
plotshape(plotLongTakeProfit, title='Long Take Profit', text='TP', textcolor = color.green, style=shape.xcross, location=location.abovebar, color=color.green, size=size.tiny)
plotshape(plotShortTakeProfit, title='Short Take Profit', text='TP', textcolor = color.red,  style=shape.xcross, location=location.belowbar, color=color.red, size=size.tiny)


// ************ Alert Conditions **************

alertcondition(buy, 'Buy Signal', '{{ticker}} | {{interval}} | Buy signal alert. Time to open a long position or close a short position, or both... Make sure the price is closing above the moving average.')
alertcondition(sell, 'Sell Signal', '{{ticker}} | {{interval}} | Sell signal alert. Time to close your long position or open short position, or both...Make sure the price is closing below the moving average.')
alertcondition(longTakeProfit, "Long Take Profit", "{{ticker}} | {{interval}} | Price has closed below the upper zone line of Bollinger Bands. Suggested Take Profit point for a LONG trade or early SHORT signal")
alertcondition(shortTakeProfit, "Short Take Profit", "{{ticker}} | {{interval}} | Price has closed above the lower zone line of Bollinger Bands. Suggested Take Profit point for SHORT trade or early LONG signal")
alertcondition(close > basis, "Bullish cross of basis line", "{{ticker}} | {{interval}} | Price has closed above the basis line of Bollinger Bands. Time to start paying attention for buy signals")
alertcondition(close < basis, "Bearish cross of basis line", "{{ticker}} | {{interval}} | Price has closed below the basis line of Bollinger Bands. Time to start paying attention for sell signals")
alertcondition(momentum and momentum[1] != momentum, "Momentum Release", "Momentum Release : {{ticker}} | {{interval}} | Momentum has picked up, check the direction of the release.")